package com.dpj.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;


@Slf4j(topic = "c.CustomLock")
public class CustomLock {

    public static void main(String[] args) {
        Mylock mylock=new Mylock();
        new Thread(()->{
            mylock.lock();
            try {
                log.debug("locking");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                log.debug("unlocking");
                mylock.unlock();
            }
        },"t1").start();
        new Thread(()->{
            mylock.lock();
            try {
                log.debug("locking");
            }finally {
                log.debug("unlocking");
                mylock.unlock();
            }
        },"t2").start();
    }

    
}
// custom lock (no reentrant lock)
class Mylock implements Lock{

    //exclusive lock   (synchronizer)
    class MySync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
//                lock,and set  the 'owner' to be the current thread
                setExclusiveOwnerThread(Thread.currentThread());
                return  true;
            }
           return  false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }


        public  Condition newCondition(){
            return new ConditionObject();
        }
    }

    private MySync mySync=new MySync();
    @Override //  lock(if failed,will go into the blocked queue)
    public void lock() {
        mySync.acquire(1);
    }

    @Override //lock ,cloud be interrupted
    public void lockInterruptibly() throws InterruptedException {
        mySync.acquireInterruptibly(1);
    }

    @Override //try to lock( one time)
    public boolean tryLock() {
        return mySync.tryAcquire(1);
    }

    @Override // try to lock(with timeout)
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return mySync.tryAcquireNanos(1,unit.toNanos(time));
    }

    @Override //unlock
    public void unlock() {
            mySync.release(1);
    }

    @Override //create the  conditional variable
    public Condition newCondition() {

       return mySync.newCondition();
    }

    }
